import { Graph, Node } from '@antv/x6';
import { register } from '@antv/x6-react-shape';
import { FunctionComponent, MouseEventHandler, ReactNode } from 'react';

import { colors } from '@/config/theme';
import { NODE_TYPE, TNodeType } from '@/constants/config';

import { CriteriaItem, LogicExpressionAssignment } from '../Rules';

export type NodeDataTypes = {
  [NODE_TYPE.START]?: {};
  [NODE_TYPE.END]?: {};
  [NODE_TYPE.DATA_LOAD]?: {
    dataSource?: string;
    tableName?: string;
    columns?: string[];
    criteria?: CriteriaItem;
  };
  [NODE_TYPE.API]?: {
    actionId?: number;
  };
  [NODE_TYPE.RULE]?: {
    rulesList: {
      criteria: CriteriaItem;
      assignments: LogicExpressionAssignment[];
    }[];
    /** 是否开启集合判断 */
    enableListOperator?: boolean;
    /** ANY_MATCH, ALL_MATCH, NONE_MATCH, HALF_MATCH, ONE_THIRD_MATCH */
    listOperator?: string;
  };
  [NODE_TYPE.MANUAL]?: {};
  [NODE_TYPE.DATA_MODIFY]?: {
    dataSource?: string;
    tableName?: string;
    mapping?: Record<string, string>;
    criteria?: CriteriaItem;
  };
  [NODE_TYPE.BASE_EDGE]?: {
    criteria: CriteriaItem;
  };
};

export interface BaseNodeProps<NT extends keyof NodeDataTypes> {
  nodeType?: keyof typeof NODE_TYPE;
  data?: NodeDataTypes[NT];
  node?: Node;
  privateVariables?: VariableItem[];
  publicVariables?: VariableItem[];
  nodeName?: string;
  onStartDrag?: (e: React.MouseEvent<Element, globalThis.MouseEvent>, data: any) => any;
  onClick?: MouseEventHandler<HTMLElement>;
  graph?: Graph;
  children?: React.ReactNode;
  className?: string;
  status?: 'INIT' | 'WAITING' | 'RUNNING' | 'FAILED' | 'FINISHED' | 'INTERRUPT';
  /** 是否阻塞节点 */
  blocked?: boolean;
  extra?: ReactNode;
}

export const defineComponentAndRegisterToGraph = (shape: TNodeType, Component: FunctionComponent<BaseNodeProps<any>>) => {
  register({
    shape,
    width: 150,
    height: 40,
    component: (props) => <Component {...props} />,
    ports: {
      groups: {
        in: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: colors.gray[400],
              strokeWidth: 1,
              fill: '#fff'
            }
          }
        },
        out: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: colors.gray[400],
              strokeWidth: 1,
              fill: '#fff'
            }
          }
        }
      }
    }
  });

  return Component;
};
